package com.ld.security.auth.server.modules.ge.service.impl;

import com.ld.security.auth.server.modules.ge.constant.GeFieldConstant;
import com.ld.security.auth.server.modules.ge.constant.GeModelConstant;
import com.ld.security.auth.server.modules.ge.entity.*;
import com.ld.security.auth.server.modules.ge.po.GenteratorCodePo;
import com.ld.security.auth.server.modules.ge.po.GrpupGetFieldPo;
import com.ld.security.auth.server.modules.ge.po.GrpupGetFieldTelPo;
import com.ld.security.auth.server.modules.ge.po.UpdateModelPo;
import com.ld.security.auth.server.modules.ge.service.*;
import com.ld.security.auth.server.modules.ge.vo.ModelDetailVo;
import com.ld.security.common.core.base.column.ListString;
import com.ld.security.common.core.base.column.MapJson;
import com.ld.security.common.mybatis.base.po.IdsPo;
import com.ld.security.common.core.base.po.SuperPo;
import com.ld.security.common.core.exception.ApiException;
import com.ld.security.common.core.util.ReflectionUtil;
import com.ld.security.common.core.util.TemplateUtil;
import com.ld.security.common.mybatis.base.service.ISuperServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
@CacheConfig(cacheNames = "geModelCache")
class GeModelServiceImpl extends ISuperServiceImpl<GeModel> implements
        IGeModelService {

    @Autowired
    private IGeModelTelService iGeModelTelService;

    @Autowired
    private IGeFieldTelService iGeFieldTelService;

    @Autowired
    private IGeFieldService iGeFieldService;

    @Autowired
    private IGeTemplateService iGeTemplateService;
    @Autowired
    private IGeParamsService iGeParamsService;

    private static final List<String> igKeys = Arrays.asList("id", "crt", "upt", "json");


    @Cacheable
    @Override
    public List<ModelDetailVo> getAllModelDetails(SuperPo po) {
        List<GeModel> geModelList = this.all(po);
        List<String> ids = geModelList.stream().map(val -> {
            return val.getId();
        }).collect(Collectors.toList());

        Map<String, List<GeField>> fieldMap = grpupGetField(ids);
        return geModelList.stream().map(val -> {
            ModelDetailVo vo = new ModelDetailVo();
            List<GeField> geFieldList = fieldMap.get(val.getId());
            vo.setModel(val);
            geFieldList.sort((x,y) -> {
                return x.getSortVal() - y.getSortVal();
            });
            vo.setFields(geFieldList);
            return vo;
        }).collect(Collectors.toList());

    }

    @CacheEvict(allEntries = true)
    @Override
    public void updateModel(UpdateModelPo po) {
        GeModel geModel = po.getModel();
        this.save(po.getModel());
        for (GeField geField : po.getFields()) {
            geField.setModelId(geModel.getId());
        }
        iGeFieldService.saveBatch(po.getFields());
    }
    @CacheEvict(allEntries = true)
    @Override
    public int remove(SuperPo query) {
        int total = 0;
        if (query instanceof IdsPo) {
            IdsPo po = (IdsPo) query;
            total = super.remove(query);
            GrpupGetFieldPo p = new GrpupGetFieldPo();
            p.setModelId(po.getIds());
            iGeFieldService.remove(p);
        } else {
            ApiException.throw400("请使用" + IdsPo.class + "删除");
        }
        return total;
    }

    /**
     * 根据模板花费数据
     *
     * @return
     */
    private Map<String, List<GeFieldTel>> grpupGetFieldTel(Collection<String> ids) {
        GrpupGetFieldTelPo p = new GrpupGetFieldTelPo();
        p.setModelTelId(ids);
        return iGeFieldTelService.all(p).stream().collect(Collectors.groupingBy(val -> {
            return val.getModelTelId();
        }));
    }

    /**
     * 根据模型划分数据
     *
     * @return
     */
    private Map<String, List<GeField>> grpupGetField(Collection<String> ids) {
        GrpupGetFieldPo p = new GrpupGetFieldPo();
        p.setModelId(ids);
        return iGeFieldService.all(p).stream().collect(Collectors.groupingBy(val -> {
            return val.getModelId();
        }));
    }


    private boolean isTree(List<GeFieldTel> fieldTels) {
        for (GeFieldTel fieldTel : fieldTels) {
            if (fieldTel.getColumnName().equals("parent_path")) {
                return true;
            }
        }
        return false;

    }
    @CacheEvict(allEntries = true)
    @Override
    public int initModel(IdsPo po) {
        Map<String, List<GeFieldTel>> getFieldTelMap = grpupGetFieldTel(po.getIds());

        for (GeModelTel geModelTel : iGeModelTelService.all(po)) {
            List<GeFieldTel> geFieldTelList = getFieldTelMap.get(geModelTel.getId());


            GeModel geModel = ReflectionUtil.clone(geModelTel, GeModel.class);
            geModel.setModelTelId(geModelTel.getId());
            geModel.setLabel(geModelTel.getTableComment());
            if (this.isTree(geFieldTelList)) {

                geModel.setTableType(GeModelConstant.tableType.Tree);
            } else {
                geModel.setTableType(GeModelConstant.tableType.Super);

            }

            String serverUrl = TemplateUtil.columnToJava(geModelTel.getTableName());
            String clientUrl = geModelTel.getTableSchema().replace("_", "-");

            ListString requestUrls = new ListString();
            requestUrls.add(clientUrl);
            requestUrls.add(serverUrl);
            geModel.setRequestUrls(requestUrls);

            this.save(geModel);


            MapJson mapJson = new MapJson();
            mapJson.put("showKey", "label");
            mapJson.put("fieldKey", "id");
            int sortVal = 0;
            for (GeFieldTel feFieldTel : geFieldTelList) {
                GeField geField = ReflectionUtil.clone(feFieldTel, GeField.class);
                geField.setFieldType(GeFieldConstant.fieldType.tel);
                geField.setModelId(geModel.getId());
                geField.setFieldTelId(feFieldTel.getId());
                geField.setFieldName(TemplateUtil.columnToJava(feFieldTel.getColumnName()));
                geField.setMapJson(mapJson);
                geField.setSortVal(sortVal++);
                geField.setSpan(8);
                boolean ig = false;
                for (String igKey : igKeys) {
                    if (geField.getColumnName().contains(igKey)) {
                        ig = true;
                        break;
                    }
                }
                if (!ig) {
                    geField.setShowQuery(true);
                    geField.setShowTable(true);
                    geField.setShowUpdate(true);
                    geField.setShowDetails(true);
                }
                String columnType = geField.getColumnType();

                String inputType = "input";
                if (columnType.contains("date")) {
                    inputType = "date-time";
                } else if (columnType.contains("tinyint")) {

                    inputType = "boolean";
                } else if (columnType.contains("int")) {

                    inputType = "input-number";
                }
                geField.setInputType(inputType);

                iGeFieldService.save(geField);

            }


        }

        return po.getIds().size();
    }


    @Override
    public byte[] genteratorCode(GenteratorCodePo po) {


        List<GeModel> geModelList = this.listByIds(po.getModelIds());
        Map<String, List<GeField>> geFieldMap = this.grpupGetField(po.getModelIds());

        GeParams geParams = iGeParamsService.getById(po.getParamsId());

        List<GeTemplate> geTemplateList = iGeTemplateService.listByIds(po.getTemplateIds());

        HashMap zipMap = new HashMap<>();


        for (GeModel geModel : geModelList) {
            List<GeField> geFieldList = geFieldMap.get(geModel.getId());
            String fileName = TemplateUtil.tableToClass(geModel.getTableName());
            for (GeTemplate geTemplate : geTemplateList) {
                Map<String, Object> map = new HashMap<>();
                map.put("className", fileName);
                map.put("modelEntity", geModel);
                map.put("fieldEntitys", geFieldList);
                String basePath;
                if(geTemplate.getTemplateType().equals(".java")){
                    basePath = geParams.getBasePath().replace("/", ".");
                }else{
                    basePath =  geParams.getBasePath();
                }

                map.put("basePath", basePath);
                map.put("paramsEntity", geParams);

                map.put("templateEntity", geTemplate);

                String name = geParams.getBasePath().replace(".", "/") + File.separator + geParams.getModuleName() + File.separator + geTemplate.getModuleName().replace(".", "/") + File.separator + geTemplate.getNamePrefix() + fileName + geTemplate.getNameSuffix() + geTemplate.getTemplateType();

                String content = geTemplate.getContent();

                String code = TemplateUtil.renderString(content, map);

                zipMap.put(name, code);
            }
        }
        return TemplateUtil.createTemplateZip(zipMap);

    }
}
